package main

import (
	"fmt"
	"math/rand"
	"math"
    "math/cmplx"
    "runtime"
    "time"
    "strings"
)

// 声明变量列表
var c,python,java,php bool

// 变量的初始化
var i,j int = 1,2

// 基本类型
var (
    ToBe bool = false
    MaxInt uint64 = 1<<64 - 1
    z complex128 = cmplx.Sqrt(-5 + 12i)
)

// 常量
const Pi = 3.14

// 数值常量
const (
    Big = 1 << 100
    Small = Big >> 99
)

func needInt(x int) int {
    return x*10 + 1
}

func needFloat(x float64) float64 {
    return x
}

func split(sum int) (x, y,a int){
    x = sum *  4 / 9
    y = sum - x
    a = sum
    return
}

func add(x int,y int) int{
    return x + y
}

func swap(x string,y string) (string,string){
    return y, x
}

// if
func sqrt(x float64) string {
    if x < 0 {
        return sqrt(-x) + "i"
    }
    return fmt.Sprint(math.Sqrt(x))
}

// if简短语句
func pow(x,n,lim float64) float64{
    if v := math.Pow(x,n); v < lim {
        return v
    }
    return lim
}

// if和else
func pow2(x,n,lim float64) float64{

    if v := math.Pow(x,n); v < lim{
        return v
    }else {
        fmt.Println(lim)
    }

    return lim
}

// switch
func testSwitch() string{
    result := ""
    switch os := runtime.GOOS; os {
    case "darwin":
        result = "Max Os"
    case "linux":
        result = "linux"
    default:
        result = os
    }
    return result
}

// switch的求值顺序
func testSwitch2() string{
    result := ""
    today := time.Now().Weekday()
    switch time.Saturday {
    case today + 0:
        result = "Today."
    case today + 1:
        result = "Tomorrow."
    case today + 2:
        result = "In two days."
    default:
        result = "Too far away."
    }
    return result
}

// 切片的长度与容量
func printtSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n",len(s),cap(s),s)
}

// 练习切片
func Pic(dx, dy int) [][]uint8 {
    a:=make([][]uint8,dy)
     for x := range a{
        b := make([]uint8,dx)
        for y := range b{
            b[y] = uint8(x*y)
        }
        a[x] = b
    }
    return a
}

// 练习 映射
func WordCount(s string) map[string]int {
	arr := strings.Fields(s)//分割成数组
	map_s := make(map[string]int)//创建map
	for _,v := range arr{
		_, ok := map_s[v]//判断map中是否存在当前字符串为下标的值
		if(ok){
			map_s[v] += 1;//存在+1
		}else{
			map_s[v] = 1;//不存在赋值为1;
		}
	}
	return map_s;
}

// 函数值
func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}
func fn(x,y float64) float64{
    return x*y
}

// 函数的闭包
func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

// 练习 斐波那契
func fibonacci() func () int {
    back1, back2 := 0, 1
    return func() int {
        temp := back1
        back1,back2 = back2,(back1+back2)
        return temp
    }
}

func main() {
    fmt.Println("Hello, World!",rand.Intn(11))
    fmt.Println("math",math.Sqrt(7))
    fmt.Println("pi",math.Pi)
    fmt.Println(add(55,11))
    a,b := swap("a","b")
    fmt.Println(a, b)

    // 命名返回值
    fmt.Println(split(55))

    // 变量
    java := true
    fmt.Println(c,python,java)

    // 变量的初始化
    fmt.Println(i,j)

    // 短变量声明
    k := 1
    fmt.Println(k)

    // 基本类型
    fmt.Printf("Type: %T Value: %v\n",ToBe,ToBe)
    fmt.Printf("Type: %T Value: %v\n",MaxInt,MaxInt)
    fmt.Printf("Type: %T Value: %v\n",z,z)

    // 零值
    var l int
    var n bool
    var c uint
    var d string
    fmt.Println(l,n,c,d)

    // 类型转换 -- 需要显式转换
    var o int = 42
    var f float64 = float64(o)
    fmt.Println(o,f)

    // 类型推导
    p := 90.00
    fmt.Printf("Type: %T Value: %v\n",p,p)

    // 常量
    const World = "世界"
    fmt.Println("Hello", World)

    // 数值常量
    fmt.Println(needFloat(Big))

    // for
    forsum := 1
    for i := 0; i < 10; i++ {
        forsum += i
    }
    fmt.Println("for: ",forsum)

    // for 续
    sum := 1
    for ;sum < 10;{
        sum += sum
    }
    fmt.Println("for 续",sum)

    // for是go中的while
    whilesum := 1
    for whilesum < 1000 {
        whilesum += whilesum
    }
    fmt.Println("while",whilesum)

    // 无限循环
    for {
        fmt.Println("无限循环")
        break
    }

    // if
    fmt.Println("if",sqrt(10))

    // if的简短语句 - 在表达式之前执行一个简单的语句
    fmt.Println(pow(1,2,3))

    // if和else
    fmt.Println("if和else",pow2(2,2,4))

    // switch
    fmt.Println("os:",testSwitch())

    // switch的求值顺序
    fmt.Println(testSwitch2())

    // 没有条件的switch
    t := time.Now()
    switch {
    case t.Hour() < 12:
        fmt.Println("Good morning!")
    case t.Hour() < 17:
        fmt.Println("Good arternoon!")
    default:
        fmt.Println("Good evening!")
    }

    // defer
    defer fmt.Println("world!")
    fmt.Println("hello")

    // defer
    fmt.Println("counting")
    for i := 0; i < 10; i++ {
        // defer fmt.Println(i)
    }
    fmt.Println("done")

    // 指针
    m := 67
    g := &m
    fmt.Println(g) // 打印的是m的内存地址
    *g = 22 // 通过g修改m
    fmt.Println(m)

    // 结构体
    type Vertex struct {
        X int
        Y int
    }

    // 结构体
    fmt.Println(Vertex{1,2})

    // 结构体字段
    type Test struct {
        X int
        Y int
    }
    v := Test{3,6};
    fmt.Println(v.X)

    // 结构体指针
    type Test2 struct {
        X int
        Y int
    }
    dd := Test2{9,10}
    u := &dd
    u.X = 102
    fmt.Println(dd)

    // 结构体文法
    v1 := Vertex{1,2}
    v2 := Vertex{X:44}
    v3 := Vertex{}
    fmt.Println(v1)
    fmt.Println(v2)
    fmt.Println(v3)

    // 数组
    var a1 [10]string
    fmt.Println(a1)
    a1[0] = "Hello"
    fmt.Println(a1);

    // 切片
    primes := [6]int{2,3,5,7,11,13}
    var s []int = primes[1:4]
    fmt.Println(s)

    // 切片就像数组的引用
    names := [4]string{
        "aaa",
        "bbb",
        "ccc",
        "ddd",
    }

    fmt.Println(names)
    a2 := names[0:2]
    b2 := names[1:3]
    fmt.Println(a2,b2)
    b2[0] = "eee"
    fmt.Println(names)

    // 切片文法
    q := []int{2,3,5,7,11,13}
    fmt.Println(q)
    s1 := []struct {
        i int
        b bool
    }{
        {2,true},
        {3,true},
        {5,true},
        {7,true},
        {11,true},
        {13,true},
        {11,true},
    }
    fmt.Println(s1)

    // 切片的默认行为
    // a3 := []int{1,2,31,3,4,1,2,3}
    var a3 [10]int
    fmt.Println(a3)
    fmt.Println(a3)

    // 切片的长度与容量
    // s = []int{1,3,542,212}
    s2 := []int{2, 3, 5, 7, 11, 13}

    // 截取切片使其长度为 0
	s2 = s2[:0]
	// 拓展其长度
	s2 = s2[:4]
    printtSlice(s2)

    // nil切片
    var s3 []int
    if s3 == nil {
        fmt.Println("nil")
    }
    fmt.Println(s3)

    // 用make创建切片
    var a5 = make([]int,5,5)
    a5 = a5[:]
    fmt.Println(a5)

    // 切片的切片
    board := [][]string{
        []string{"_","_","_"},
        []string{"_","_","_"},
        []string{"_","_","_"},
    }
    board[0][0] = "X"
	board[2][2] = "O"
	board[1][2] = "X"
	board[1][0] = "O"
    board[0][2] = "X"
    for i := 0; i < len(board); i++ {
        fmt.Printf("%s\n", strings.Join(board[i], " "))
    }
    fmt.Println(board)

    // 向切片追加元素
    var s5 []int
    s5 = append(s5,12)
    s5 = append(s5,1232,12,22)
    fmt.Println(s5)

    // Range
    var pow = []int{1,2,34,5,1,23,1,2}
    for i,v := range pow {
        fmt.Println(i,v)
    }

    // Range 续
    var pow2 = []int{121,1,234,1,23}
    for _,value := range pow2 {
        fmt.Println(value)
    }

    // 练习切片
    fmt.Println(Pic(8,8))

    // 映射
    type Vertex2 struct {
        Lat, Long float64
    }
    var m22 map[string]Vertex2
    m22= make(map[string]Vertex2)
	m22["Bell Labs"] = Vertex2{
		40.68433, -74.39967,
	}
	fmt.Println(m22["Bell Labs"])

    // 映射的文法(续)
    var m33 = map[string]Vertex{
        "Test":{12221,2212},
    }
    fmt.Println(m33)

    // 修改映射
    m4 := make(map[string]int)
    m4["Test"] = 42
    fmt.Println(m4)
    m4["Test"] = 48
    fmt.Println(m4)
    delete(m4,"Test") // 删除元素
    fmt.Println(m4)
    elem,ok := m4["Test"]
    fmt.Println(elem,ok)   
    
    // 练习 映射
    fmt.Println(WordCount("qwasdasd"))

    // 函数值
    fmt.Println(compute(fn))
    fn1 := func(x,y float64) float64{
        return math.Sqrt(x*x)
    }
    fmt.Println(fn1(1,2))

    // 函数的闭包
    pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}

    // 练习 斐波那契
    f3 := fibonacci()
    for i = 0;i < 10;i++{
        fmt.Println(f3())
    }


}
